<?php
namespace framework\driver\mysql;

use \PDO;

/**
 * PDO 数据处理类
 */
class Helper
{
    /**
     * 连接实例
     *
     * @var \PDO
     */
    private $client;
    /**
     * 数据表名
     *
     * @var string
     */
    private $tableName;
    /**
     * 类名
     *
     * @var string
     */
    private $className;

    /**
     * 构造函数
     *
     * @param string $className
     */
    public function __construct($className)
    {
        $this->className = $className;
        $this->client = Manager::getInstance();
    }

    /**
     * 构造更新字段
     *
     * @param string $field
     * @return string
     */
    private static function updateFieldMap($field)
    {
        return '`' . $field . '`=:' . $field;
    }

    /**
     * 构造更新字段
     *
     * @param string $field
     * @return string
     */
    private static function changeFieldMap($field)
    {
        return '`' . $field . '`=`' . $field . '`+:' . $field;
    }

    /**
     * 取得表名
     *
     * @return string
     */
    function getTableName()
    {
        if (empty($this->tableName))
        {
            $classRef = new \ReflectionClass($this->className);
            $this->tableName = $classRef->getConstant('TABLE_NAME');
        }

        return $this->tableName;
    }

    /**
     * 取得类名
     *
     * @return string
     */
    function getClassName()
    {
        return $this->className;
    }

    /**
     * 取得连接实例
     *
     * @return \PDO
     */
    function getClient()
    {
        return $this->client;
    }

    /**
     * 添加一个对象
     *
     * @param object $entity
     * @param array  $fields
     * @param string $onDuplicate
     * @return int
     */
    public function add($entity, $fields, $onDuplicate = null)
    {
        $strFields = '`' . implode('`,`', $fields) . '`';
        $strValues = ':' . implode(', :', $fields);

        $query = "INSERT INTO `{$this->getTableName()}` ({$strFields}) VALUES ({$strValues})";

        if (!empty($onDuplicate))
        {
            $query .= 'ON DUPLICATE KEY UPDATE ' . $onDuplicate;
        }

        $statement = $this->client->prepare($query);
        $params = array();

        foreach ($fields as $field)
        {
            $params[$field] = $entity->$field;
        }

        $statement->execute($params);
        return $this->client->lastInsertId();
    }

    /**
     * 添加多个对象
     *
     * @param array $entitys
     * @param array $fields
     * @return boolean
     */
    public function addMulti($entitys, $fields)
    {
        $items = array();
        $params = array();

        foreach ($entitys as $index => $entity)
        {
            $items[] = '(:' . implode($index . ', :', $fields) . $index . ')';

            foreach ($fields as $field)
            {
                $params[$field . $index] = $entity->$field;
            }
        }

        $query = "INSERT INTO `{$this->getTableName()}` (`" . implode('`,`', $fields) . "`) VALUES " . implode(',', $items);
        $statement = $this->client->prepare($query);
        return $statement->execute($params);
    }

    /**
     * 替换模式添加一个对象
     *
     * @param object $entity
     * @param array  $fields
     * @return int
     */
    public function replace($entity, $fields)
    {
        $strFields = '`' . implode('`,`', $fields) . '`';
        $strValues = ':' . implode(', :', $fields);

        $query = "REPLACE INTO `{$this->getTableName()}` ({$strFields}) VALUES ({$strValues})";
        $statement = $this->client->prepare($query);
        $params = array();

        foreach ($fields as $field)
        {
            $params[$field] = $entity->$field;
        }

        $statement->execute($params);
        return $this->client->lastInsertId();
    }

    /**
     * 更新所有符合条件的对象
     *
     * @param array   $fields
     * @param array   $params
     * @param string  $where
     * @param boolean $change
     * @return boolean
     */
    public function update($fields, $params, $where, $change = false)
    {
        if ($change)
        {
            $updateFields = array_map(__CLASS__ . '::changeFieldMap', $fields);
        }
        else
        {
            $updateFields = array_map(__CLASS__ . '::updateFieldMap', $fields);
        }

        $strUpdateFields = implode(',', $updateFields);
        $query = "UPDATE `{$this->getTableName()}` SET {$strUpdateFields} WHERE {$where}";
        $statement = $this->client->prepare($query);
        return $statement->execute($params);
    }

    /**
     * 取得符合条件的第一条记录的第一个值
     *
     * @param string $where
     * @param array  $params
     * @param string $fields
     * @return mixed
     */
    public function fetchValue($where = '1', $params = null, $fields = '*')
    {
        $query = "SELECT {$fields} FROM `{$this->getTableName()}` WHERE {$where} limit 1";
        $statement = $this->client->prepare($query);
        $statement->execute($params);
        return $statement->fetchColumn();
    }

    /**
     * 取得所有符合条件数据的第一列（一维数组）
     *
     * @param string $where
     * @param array  $params
     * @param string $fields
     * @param string $orderBy
     * @param string $limit
     * @return array
     */
    public function fetchCol($where = '1', $params = null, $fields = '*', $orderBy = null, $limit = null)
    {
        $results = $this->fetchArray($where, $params, $fields, $orderBy, $limit);
        return empty($results) ? array() : array_map('reset', $results);
    }

    /**
     * 取得所有符合条件的数据（数组）
     *
     * @param string $where
     * @param array  $params
     * @param string $fields
     * @param string $orderBy
     * @param string $limit
     * @return array
     */
    public function fetchArray($where = '1', $params = null, $fields = '*', $orderBy = null, $limit = null)
    {
        $query = "SELECT {$fields} FROM `{$this->getTableName()}` WHERE {$where}";

        if ($orderBy)
        {
            $query .= " ORDER BY {$orderBy}";
        }

        if ($limit)
        {
            $query .= " limit {$limit}";
        }

        $statement = $this->client->prepare($query);
        $statement->execute($params);
        $statement->setFetchMode(PDO::FETCH_ASSOC);
        return $statement->fetchAll();
    }

    /**
     * 取得所有符合条件的对象
     *
     * @param string $where
     * @param array  $params
     * @param string $fields
     * @param string $orderBy
     * @param string $limit
     * @return array
     */
    public function fetchAll($where = '1', $params = null, $fields = '*', $orderBy = null, $limit = null)
    {
        $query = "SELECT {$fields} FROM `{$this->getTableName()}` WHERE {$where}";

        if ($orderBy)
        {
            $query .= " order by {$orderBy}";
        }

        if ($limit)
        {
            $query .= " limit {$limit}";
        }

        $statement = $this->client->prepare($query);
        $statement->setFetchMode(PDO::FETCH_CLASS, $this->className);
        return $statement->fetchAll();
    }

    /**
     * 取得符合条件的一个对象
     *
     * @param string $where
     * @param array  $params
     * @param string $fields
     * @param string $orderBy
     * @return object
     */
    public function fetchEntity($where = '1', $params = null, $fields = '*', $orderBy = null)
    {
        $query = "SELECT {$fields} FROM `{$this->getTableName()}` WHERE {$where}";

        if ($orderBy)
        {
            $query .= " order by {$orderBy}";
        }

        $query .= " limit 1";
        $statement = $this->client->prepare($query);
        $statement->execute($params);
        $statement->setFetchMode(PDO::FETCH_CLASS, $this->className);
        return $statement->fetch();

    }

    /**
     * 删除所有符合条件的数据
     *
     * @param string $where
     * @param array  $params
     * @return int
     */
    public function remove($where, $params)
    {
        if (empty($where))
        {
            return false;
        }

        $query = "DELETE FROM `{$this->getTableName()}` WHERE {$where}";
        $statement = $this->client->prepare($query);
        return $statement->execute($params);
    }
}